/*
 * Created by: Sam Olmsted
 * 3/28/11
 */
#include "fair_sched.h"

/*
 * Init Groups 
 */

int setup_groups(int number)
{
    int i = 0;
    struct group * group;

    for(i; i<number; i++)
    {
        group = (struct group *) malloc(sizeof(struct group *));

        enqueue_group(&empty_groups, group);
        n_groups++;
        n_empty_groups++;
    }

    return 1;
}

/*
 * Group Functions
 */

struct group *
dequeue_group(struct group ** dequeue)
{
    struct group * group;

    group = (*dequeue)->prev;

    group->next->prev = group->prev;
    group->prev->next = group->next;

    return group;
}

struct group *
enqueue_group(struct group ** enqueue, struct group * insert)
{
    /*
     * Empty Group
     */
    if( *enqueue == NULL )
    {
        insert->next = insert;
        insert->prev = insert;

        *enqueue = insert; 
        return *enqueue;

    }

    /*
     * Group is not empty
     */
    insert->next = (*enqueue);
    insert->prev = (*enqueue)->prev;

    (*enqueue)->prev       = insert; 
    (*enqueue)->prev->next = insert; 

    return (*enqueue);
}

/*
 * Process Management in Groups
 */

int                 
add_to_group( struct process_struct * insert, int gid)
{
    int i = 0;
    int found = 0;
    int active = n_groups - n_empty_groups;

    struct group * group = groups;

    for(i; i< active; i++)
    {
        if( group->gid == gid)
        {
            found = 1;
            break;
            
        }
        group = group->next;
    }

    /*Create a new group*/
    if(found == 0)
    {
        if(n_empty_groups == 0)
        {
            printf("No more groups, can not add your process to a new group\n");
            
            return 0;
        }

        group = dequeue_group( &empty_groups );
        group->gid = gid;
        group->size = 0;

        enqueue_bundle( &(group->bundle), insert, &(group->size));   

    } else { //add to existing group
        enqueue_bundle( &(group->bundle), insert, &(group->size));   

    }

    return 1;
}

struct process_struct *
remove_from_group(int pid);


/*
 * Bundle Funcitons  
 */

struct process_struct *
dequeue_bundle(struct process_struct ** queue, int * size)
{
    struct process_struct * removed;
    removed = (struct process_struct *) dequeue(queue, size);

    return removed;
}

struct process_struct * 
enqueue_bundle(struct process_struct ** queue, struct process_struct * insert, int * size)
{
    struct process_struct * head;
    head = (struct process_struct *) dequeue(queue, insert, size);

    return head;
}


/*
 * Stats
 */

int group_stats()
{
    int i = 0;
    int active = n_groups - n_empty_groups;
    struct group * group = groups;
    
    printf("number of groups: %d\n" 
           "number of active: %d\n", n_groups, active);

    if( active != 0)
    {
        printf("Group     : Number of Processes\n");
    }

    for(i; i<active; i++)
    {
        printf("group [%d]: %d\n", group->gid, group->size);
        group = group->next; 

    }

    printf("\n");
    return 1;
}
